#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <stdbool.h>
#include <stdlib.h>
#include <signal.h>
#include <stdint.h>
#include <net/if.h>

// 可配置参数
#define LOG_FILE "switch_events.csv"

// 全局变量用于记录主备切换时间
static volatile sig_atomic_t running = 1;
static struct timespec primary_down_time = {0, 0};
static struct timespec backup_up_time = {0, 0};
static char primary_ifname[IFNAMSIZ] = {0};
static char backup_ifname[IFNAMSIZ] = {0};

// 函数声明
int get_bond_slave_info(const char *bond_name, char *primary_slave, char *backup_slave, size_t len);

// 错误代码定义
typedef enum {
    ERR_SOCKET = -1,
    ERR_BIND = -2,
    ERR_FILE = -3
} error_code;

// 上下文配置结构体
typedef struct {
    char bond_ifname[16];
    int log_level;
    uint32_t netlink_groups;
} monitor_config;

struct switch_event {
    long timestamp;
    char interface[16];
    int event_type;
};

// 带错误码返回的增强版本
int record_switch_event(const monitor_config *cfg, int type, const char *ifname, bool is_primary) {
    if(!cfg) return ERR_FILE;
    struct timespec ts;
    clock_gettime(CLOCK_REALTIME, &ts);
    
    FILE *fp = fopen("switch_events.csv", "a");
    if(fp) {
        fprintf(fp, "%ld.%03ld,%s,%d\n", 
               ts.tv_sec, ts.tv_nsec/1000000, ifname, type);
        fclose(fp);
    }
    
    // 根据事件类型打印不同的信息
    // 检查接口是否处于活动状态
    if (type & IFF_RUNNING) {
        printf("%ld.%03ld - 网络恢复正常，数据从 %s 口传送\n", ts.tv_sec, ts.tv_nsec/1000000, ifname);
        
        // 记录备网口恢复时间
        if (!is_primary) {
            backup_up_time = ts;
            printf("%ld.%03ld - 切换到备网口 %s\n", ts.tv_sec, ts.tv_nsec/1000000, ifname);
            
            // 计算切换时间
            if (primary_down_time.tv_sec != 0 || primary_down_time.tv_nsec != 0) {
                long long switch_time_ms = (ts.tv_sec - primary_down_time.tv_sec) * 1000 + 
                                          (ts.tv_nsec - primary_down_time.tv_nsec) / 1000000;
                printf("切换时间: %lld ms\n", switch_time_ms);
                
                // 重置时间戳
                primary_down_time.tv_sec = 0;
                primary_down_time.tv_nsec = 0;
            }
        }
    } 
    // 检查接口是否断开
    else if (!(type & IFF_RUNNING)) {
        printf("%ld.%03ld - 拔掉了 %s 口的网线\n", ts.tv_sec, ts.tv_nsec/1000000, ifname);
        
        // 记录主网口断开时间
        if (is_primary) {
            primary_down_time = ts;
            printf("%ld.%03ld - 主网口 %s 断开\n", ts.tv_sec, ts.tv_nsec/1000000, ifname);
        }
    }
    // 其他状态变化
    else {
        printf("%ld.%03ld - 接口 %s 状态变化: %d\n", ts.tv_sec, ts.tv_nsec/1000000, ifname, type);
    }
}

// 配置初始化函数
static void init_config(monitor_config *cfg, const char *primary, const char *backup) {
    // 设置默认bond接口名称为primary接口名称
    strncpy(cfg->bond_ifname, primary, 15);
    cfg->bond_ifname[15] = '\0';
    cfg->log_level = 1;
    cfg->netlink_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
    
    // 设置主备接口信息
    strncpy(primary_ifname, primary, IFNAMSIZ-1);
    primary_ifname[IFNAMSIZ-1] = '\0';
    strncpy(backup_ifname, backup, IFNAMSIZ-1);
    backup_ifname[IFNAMSIZ-1] = '\0';
    
    printf("主接口: %s\n", primary_ifname);
    printf("备接口: %s\n", backup_ifname);
}

// 信号处理函数
static void sig_handler(int signo) {
    // 保存缓冲区数据
    exit(0);
}

// 添加内存安全机制
#define SAFE_FREE(ptr) do { \
    if(ptr) { free(ptr); ptr = NULL; } \
} while(0)

// 获取bond接口的主备状态
int get_bond_slave_info(const char *bond_name, char *primary_slave, char *backup_slave, size_t len) {
    char path[256];
    snprintf(path, sizeof(path), "/proc/net/bonding/%s", bond_name);
    
    FILE *fp = fopen(path, "r");
    if (!fp) {
        perror("fopen");
        return -1;
    }
    
    char line[256];
    bool found_primary = false;
    bool found_backup = false;
    
    while (fgets(line, sizeof(line), fp)) {
        if (strncmp(line, "Primary Slave: ", 15) == 0) {
            strncpy(primary_slave, line + 15, len - 1);
            primary_slave[len - 1] = '\0';
            
            // 移除换行符
            char *newline = strchr(primary_slave, '\n');
            if (newline) {
                *newline = '\0';
            }
            
            found_primary = true;
        }
        
        // 注意：这里简化处理，实际可能需要解析所有Slave接口来确定备接口
        // 在active-backup模式下，通常只有一个Primary Slave，其他都是备
        if (strncmp(line, "Slave Interface: ", 17) == 0 && !found_primary) {
            strncpy(backup_slave, line + 17, len - 1);
            backup_slave[len - 1] = '\0';
            
            // 移除换行符
            char *newline = strchr(backup_slave, '\n');
            if (newline) {
                *newline = '\0';
            }
            
            found_backup = true;
        }
    }
    
    fclose(fp);
    return (found_primary || found_backup) ? 0 : -1;
}

// 增强配置管理
struct config {
    uint32_t sampling_interval;
    bool daemon_mode;
    char log_path[256];
};

int main(int argc, char **argv) {
    // 检查命令行参数
    if (argc != 3) {
        fprintf(stderr, "用法: %s <主网口> <备网口>\n", argv[0]);
        exit(1);
    }
    
    // 解析命令行参数
    monitor_config cfg;
    init_config(&cfg, argv[1], argv[2]);
    // 添加信号处理器
    signal(SIGINT, sig_handler);
    signal(SIGTERM, sig_handler);
    int sockfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
    if (sockfd < 0) {
        perror("socket");
        return ERR_SOCKET;
    }
    struct sockaddr_nl sa;
    memset(&sa, 0, sizeof(sa));
    sa.nl_family = AF_NETLINK;
    sa.nl_groups = cfg.netlink_groups;
    if (bind(sockfd, (struct sockaddr*)&sa, sizeof(sa)) < 0) {
        perror("bind");
        close(sockfd);
        return ERR_BIND;
    }
    
    // 实时解析网络接口状态变化
    while(1) {
        char buf[4096];
        struct iovec iov = {buf, sizeof(buf)};
        struct msghdr msg = {0, 0, &iov, 1, NULL, 0, 0};
        ssize_t len = recvmsg(sockfd, &msg, 0);
        if (len < 0) {
            perror("recvmsg");
            continue;
        }
        
        struct nlmsghdr *nh;
        for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) {
            if (nh->nlmsg_type == NLMSG_DONE) break;
            if (nh->nlmsg_type == NLMSG_ERROR) {
                perror("NLMSG_ERROR");
                break;
            }
            
            struct ifinfomsg *ifi = NLMSG_DATA(nh);
            if (ifi->ifi_family == AF_UNSPEC) {
                // 获取接口名称
                char ifname[IFNAMSIZ];
                if_indextoname(ifi->ifi_index, ifname);
                
                // 判断是否是主备接口之一
                if (strcmp(ifname, primary_ifname) == 0 || strcmp(ifname, backup_ifname) == 0) {
                    // 判断是否是主接口
                    bool is_primary = (strcmp(ifname, primary_ifname) == 0);
                    
                    // 检测到主备切换时调用record_switch_event()
                    record_switch_event(&cfg, ifi->ifi_flags, ifname, is_primary);
                }
            }
        }
    }
    
    close(sockfd);
    return 0;
}